using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using SBPweb.Presentation.Windows.Forms.Controls;
using SBPweb.Modules.ChatController.History;
using SBPweb.Controls.Windows;
using SBPweb.Controls.Windows.Editors;
using SBPweb.Controls.Windows.Editors.HelperClasses;
using SBPweb.Localization;

using Verety.SharedMeta.MessagingServiceMeta;
using Verety.SharedMeta.MessagingServiceMeta.Contacts;
using Verety.SharedMeta.MessagingServiceMeta.Connection;
using Verety.SharedMeta.MessagingServiceMeta.Conversation;
using Verety.SharedMeta.MessagingServiceMeta.Conversation.Controls;
using Verety.SharedMeta.DirectoryServiceMeta;
using Verety.SharedMeta.DirectoryServiceMeta.Conversation;
using Verety.SharedMeta.DirectoryServiceMeta.Conversation.ChatHistory;
using Verety.SharedMeta.UIMeta;
using Verety.SharedMeta.UIMeta.Common;
using Verety.SharedMeta.UIMeta.Interfaces;

using Verety.DirectoryService.Connection;

using SBPweb.Contracts.WebBrowser;
using System.Drawing.Imaging;


namespace SBPweb.Modules.ChatController.Controls
{ 
    public partial class ChatControl : DockingUserControl, IChatControl, IDisposable
    {
        #region Private members

        private ChatControllerModule mChatControlManager;
        private IConversation mConversation;
		private IDirectoryService mDirectoryService;
		private SBPweb.Modules.ChatController.ChatConfiguration mChatConfiguration;

        private ChatHistory chatHistory;
        
        private string oldConferenceName;
        private string mLastMessage = string.Empty;
        private Timer scrollBlinkTimer;
		private IContactId currentUserJID;
		private Dictionary<string, string> conferenceMembers = new Dictionary<string, string>();
		private PresenceType prevType = PresenceType.invisible;
        private bool mUpdateSrolling = true;
        private bool mFirstError = true;

        private Bitmap mDownImage = null;
        private Bitmap mDownImageHigh = null;

        private ChatControlPositionInfo mChatControlPositionInfo = new ChatControlPositionInfo();

        #endregion

        #region Delegates
        private delegate void IPresenceParameterHandler(IPresence presence);
        private delegate void mConversation_OnConversationConvertedHandler(IMessagingService messenger, IConversation conversation, IConference conference, IConversationConvertedArgs args);
        private delegate void mConversation_OnStatePresenceHandler(object sender, IStatePresence presence);
        private delegate void PresetConferenceOwnerHandler(IConference conference);
        private delegate void SetConferencePanelVisiblilityHandler(bool visibility);
        private delegate void SetControlTextHandler(Control control, string text);
        private delegate void SetControlVisibilityHandler(Control control, bool visibility);
        private delegate void SetTextBoxStyleParameteredHandler(ExtendedRichTextBox textBox, Font font, Color color);
        #endregion

        #region Public properties

        public IConversation Conversation
        {
            get
            {
                return mConversation;
            }
            private set
            {
                // Dewiring previous conversation
                if (mConversation != null)
                {
                    mConversation.OnMessage -= new MessageHandler(mConversation_OnMessage);
                    mConversation.OnStatePresence -= new StatePresenceHandler(mConversation_OnStatePresence);

                    if (mConversation is IConference)
                    {
                        (mConversation as IConference).OnJoinPresence -= new JoinPresenceHandler(mConversation_OnJoinPresence);
                        (mConversation as IConference).OnRelievePresence -= new JoinPresenceHandler(mConversation_OnRelievePresence);
                        SetCaptions("Conference");
                    }
                }

                // Make value to be current conversation and wire in
                mConversation = value;

                mConversation.OnMessage += new MessageHandler(mConversation_OnMessage);
                mConversation.OnStatePresence += new StatePresenceHandler(mConversation_OnStatePresence);
                cmbPriority.SelectedIndex = (int)mConversation.Options.Priority - 1;
                cmbPriority.SelectedIndexChanged += new EventHandler(cmbPriority_SelectedIndexChanged);

                // Conference
                if (mConversation is IConference)
                {
                    (mConversation as IConference).OnJoinPresence += new JoinPresenceHandler(mConversation_OnJoinPresence);
                    (mConversation as IConference).OnRelievePresence += new JoinPresenceHandler(mConversation_OnRelievePresence);

                    AddConferencePartner(mDirectoryService.Connection.CurrentPresence);

                    SetConferencePanelVisibility(true);

                }
                // Normal conversation
                else
                {
                    mConversation.OnConversationConverted += new ConversationConvertedHandler(mConversation_OnConversationConverted);

                    SetConferencePanelVisibility(false);

                    //initialize chatHistory
                    chatHistory = ChatHistoryManager.GetChatHistory(currentUserJID, mConversation.Partner, "Chat");
                    if (chatHistory == null && mDirectoryService.Security.Authorize("Creation:ChatHistory"))
                    {
                        chatHistory = ChatHistoryManager.CreateHistory(currentUserJID, mConversation.Partner, "Chat", mChatControlManager);
                    }

                    if (String.IsNullOrEmpty(mConversation.Partner.Resource))
                    {
                        prevType = PresenceType.unavailable;
                    }
                    else
                    {
                        prevType = PresenceType.available;
                    }
                }

                SetCaptions(string.Format(LocalizationExtender.GetString(this, "ChatWith"), mConversation.Partner.User));
            }
        }

        public string InfoMessage
        {
            get
            {
                return tslError.Text;
            }
            set
            {
				tslError.Text = value;
				if (string.IsNullOrEmpty(tslError.Text))
                {
                    tslMe.Visible = true;
					tslError.Visible = false;
                }
                else
                {
                    tslMe.Visible = false;
					tslError.Visible = true;
                }
            }
        }

        internal ChatControlPositionInfo ChatControlClosingInfo
        {
            get
            {
                return mChatControlPositionInfo;
            }
        }

        #endregion

        #region Private invoked helper methods

        private void SetConferencePanelVisibility(bool visibility)
        {
			if (InvokeRequired)
            {
                Invoke(new SetConferencePanelVisiblilityHandler(SetConferencePanelVisibility), new object[] { visibility });
                return;
            }

            if (visibility)
            {
                splitContainer2.Panel1Collapsed = false;
                splitContainer2.Panel2Collapsed = false;
                btnHide.Text = "<";
            }
            else
            {
                splitContainer2.Panel1Collapsed = true;
                splitContainer2.Panel2Collapsed = false;
                btnHide.Text = ">";
            }

            //if this is Conference do not hide conference any information
            if (mConversation is IConference)
            {
                tbConferenceName.Visible = btnHide.Visible = true;
                lblChatWith.Visible = false;
                ContextMenuStrip = null;
            }
            else
            {
                tbConferenceName.Visible = btnHide.Visible = false;
                lblChatWith.Visible = true;
                ContextMenuStrip = contextMenuStrip;
            }

			if (!(Conversation.Requester.User == mDirectoryService.Connection.UserContactId.User &&
				Conversation.Requester.Server == mDirectoryService.Connection.UserContactId.Server))
			{
				btnJoin.Enabled = false;
				return;
			}
        }

        private void SetCaptions(string text)
        {
            if (InvokeRequired)
            {
                Invoke(new StringParameteredHandler(SetCaptions), text);
                return;
            }
            if (Conversation is IConference && (Conversation.Options as IConferenceOptions) != null && (Conversation.Options as IConferenceOptions).IsAdministered)
            {
                text = "[" + text + "]";
            }
            Caption = text;
            lblChatWith.Text = text;
        }

        #endregion

        #region Private helper methods

        private void RenameConference()
        {
            Conversation.SendMessage(tbConferenceName.Text, null);
            SetCaptions(tbConferenceName.Text);
        }

        #endregion

        #region Conversation event handlers

		void cmbPriority_SelectedIndexChanged(object sender, EventArgs e)
		{
			mConversation.Options.Priority = (ConversationPriority)(cmbPriority.SelectedIndex + 1);
		}

		void mConversation_OnMessage(object sender, IMessage message)
        {
			if (InvokeRequired)
			{
				BeginInvoke(new MessageHandler(mConversation_OnMessage), sender, message);
				return;
			}

            if (message.Body == null)
            {
                // Changing title
                if (message.Subject != null)
                    SetCaptions(message.Subject);
            }
            else
            {
				if (message.Extensions["Type"] != null && message.Extensions["Type"].ToString() == "error")
				{
                    if (mFirstError)
                    {
                        AppendErrorText(message);
                        btnSendMessage.Enabled = false;
                        Enabled = false;
                        mFirstError = false;
                    }
				}
				else
                {
					AddIncomingText(message);
                    this.NotifyUser(message.Sender.User + " says: " + message.Body, false);
                }

				//TODO: If we want sound for background messages, put the following lines back!

				//if (ParentForm != null && !ParentForm.ContainsFocus)
				//{
				//    try
				//    {
				//        if (mChatConfiguration.PlayBackgroundSound)
				//        {
				//            System.Media.SystemSounds.Exclamation.Play();
				//        }
				//    }
				//    catch { }
				//}
			}

            if (chatHistory != null)
            {
                IHistoryEntry he = (mDirectoryService.Conversations as IDirectoryConversationManager).CreateHistoryEntryInstance(message.TimeStamp, message.Recipient, message.Sender, PacketType.Message, message);
                chatHistory.AddHistoryEntry(he);
            }
        }

        void mConversation_OnStatePresence(object sender, Verety.SharedMeta.MessagingServiceMeta.Contacts.IStatePresence presence)
        {
			if (InvokeRequired)
			{
				Invoke(new mConversation_OnStatePresenceHandler(mConversation_OnStatePresence), sender, presence);
				return;
			}

            if (sender is IConference)
            {
				string user = presence.Sender.User;
				string server = presence.Sender.Server;
				string resource = presence.Sender.Resource;
				string jid = string.Format("{0}@{1}/{2}", user, server, resource);
				string text = string.Format("{0} ({1})", user, resource);
				IContactId contactID = mDirectoryService.Contacts.CreateContactId(user + "@" + server);
				if ((Conversation as IConference).RequiredMembers.Contains(contactID))
				{
					(Conversation as IConference).Invite(contactID);
				}
				else
				{
					if (!lwConferencePartners.Items.ContainsKey(jid))
					{
						lwConferencePartners.Items.Add(jid, text, 0);
					}
					lwConferencePartners.Items[jid].ForeColor = Color.Black;
				}
            }
            else
            {
                SetCaptions(string.Format(LocalizationExtender.GetString(this, "ChatWith"), presence.Sender.Name));
				lblChatWith.ForeColor = Color.Black;

				tbInComing.SetStyle(mChatConfiguration.OtherTextFont, Color.Red);

				if (prevType != presence.Type)
				{
					if (presence.Type == PresenceType.unavailable)
					{
						string offlineWarning = LocalizationExtender.GetString(this, "OfflineWarning");
						string logout = LocalizationExtender.GetString(this, "UserLoggedOut");
						if (string.IsNullOrEmpty(offlineWarning))
							AppendText("<" + presence.Sender.Name + " " + logout + ">\nYour message will be sent offline.\n\n");
						else
							AppendText("<" + presence.Sender.Name + " " + logout + ">\n" + offlineWarning + "\n\n");
					}
					if (presence.Type == PresenceType.available)
					{
						string login = LocalizationExtender.GetString(this, "UserLoggedIn");
						AppendText("<" + presence.Sender.Name + " " + login +">\n");
					}
				}
				prevType = presence.Type;
			}
        }

        void mConversation_OnConversationConverted(IMessagingService messenger, IConversation conversation, IConference conference, IConversationConvertedArgs args)
        {
			if (InvokeRequired)
			{
				BeginInvoke(new mConversation_OnConversationConvertedHandler(mConversation_OnConversationConverted), messenger, conversation, conference, args);
				return;
			}

            Conversation = conference;
            SetConferencePanelVisibility(true);
			// set conference name
			tbConferenceName_Leave(this, null);
		}

        void mConversation_OnJoinPresence(object sender, Verety.SharedMeta.MessagingServiceMeta.Contacts.IJoinPresence presence)
        {
			AddConferencePartner(presence);
			if (mDirectoryService.Connection.UserName == (Conversation as IConference).Requester.User)
			{
				RenameConference();
			}
        }

        void mConversation_OnRelievePresence(object sender, Verety.SharedMeta.MessagingServiceMeta.Contacts.IJoinPresence presence)
        {
            RemoveConferencePartner(presence);
        }

        #endregion

        #region Partner handling

        void AddConferencePartner(IPresence presence)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new IPresenceParameterHandler(AddConferencePartner), presence);
                return;
            }
			IContactId sender = presence.Sender;
			if (sender == null)
			{
				sender = mDirectoryService.Connection.UserContactId;
			}
			// JID is not an existing thing here
			string key = string.Format("{0}@{1}/{2}", sender.Name, sender.Server, sender.Resource);
			string res = sender.Resource == null ? string.Empty : sender.Resource;
			string text = string.Format("{0} ({1})", sender.Name, res);
			string userName = sender.Name;
			if (sender.Server == Verety.SharedMeta.DirectoryServiceMeta.Enums.StringConstants.ServerNameForConferences)
			{
				string userResource = string.Empty;
				if (userName.Contains("__"))
				{
					userResource = userName.Substring(userName.LastIndexOf("__") + 2);
					if (userResource != string.Empty)
					{
						userResource = string.Format(" ({0})", userResource);
					}
					userName = userName.Substring(0, userName.LastIndexOf("__")).ToLower();
				}
				key = string.Format("{0}@{1}", sender.Name, sender.Server);
				text = string.Format("{0}{1}", userName, userResource);
			}
			bool foundValue = false;
			foreach (ListViewItem lwi in lwConferencePartners.Items)
			{
				if (lwi.Text == text)
				{
					foundValue = true;
				}
			}
			if (!foundValue && lwConferencePartners.Items.IndexOfKey(key) < 0)
			{
				if (sender.Server != Verety.SharedMeta.DirectoryServiceMeta.Enums.StringConstants.ServerNameForConferences)
				{
					string nKey = sender.Name + "@" + Verety.SharedMeta.DirectoryServiceMeta.Enums.StringConstants.ServerNameForConferences;
					if (lwConferencePartners.Items.ContainsKey(nKey))
					{
						lwConferencePartners.Items.RemoveByKey(key);
					}
				}
				ListViewItem lvi = lwConferencePartners.Items.Add(key, text, 0);
				lwConferencePartners.Items[lvi.Index].SubItems.Add(presence.Name);

				lwConferencePartners.Items[lvi.Index].ForeColor = sender.User.Equals(mConversation.Requester.User) ? mChatConfiguration.OwnerOtherTextColor : mChatConfiguration.OtherTextColor;
			}
			bool contains = false;
			if (conferenceMembers.ContainsKey(userName))
			{
				contains = true;
				conferenceMembers.Remove(userName);
			}
			conferenceMembers.Add(userName, text);
			if (!contains)
			{
				string name = userName;
				if (name.Contains("__"))
				{
					name = name.Split("__".ToCharArray())[0];
				}
				tbInComing.SetStyle(new Font(FontFamily.GenericSansSerif, 8), Color.Red);
				AppendText(name + " joined\n");
			}
		}

        void RemoveConferencePartner(IPresence presence)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new IPresenceParameterHandler(RemoveConferencePartner), presence);
                return;
            }
            int index;
			string key = string.Format("{0}@{1}{2}", presence.Sender.Name, presence.Sender.Server, presence.Sender.Resource != null ? string.Format("/{0}", presence.Sender.Resource) : string.Empty);
            if ((index = lwConferencePartners.Items.IndexOfKey(key)) >= 0)
            {
                lwConferencePartners.Items.RemoveAt(index);
            }
			tbInComing.SetStyle(new Font(FontFamily.GenericSansSerif, 8), Color.Red);
			string name = presence.Sender.Name;
			if (name.Contains("__"))
			{
				name = name.Split("__".ToCharArray())[0];
			}
			AppendText(name + " left\n");
		}

        private void lwConferencePartners_DragEnter(object sender, DragEventArgs e)
        {
            // Only strings can be dragged
            string contactidstring = e.Data.GetData(DataFormats.StringFormat) as string;
            if (contactidstring == null)
            {
                return;
            }

            e.Effect = DragDropEffects.Copy;
        }

        private void lwConferencePartners_DragDrop(object sender, DragEventArgs e)
        {
            string contactidstring = e.Data.GetData(DataFormats.StringFormat) as string;
			if (contactidstring.Split('\r').Length > 1)
			{
				contactidstring = contactidstring.Split('\r')[0];
			}

            (mConversation as IConference).Invite(contactidstring);
			if (!contactidstring.Contains("/"))
			{
				MessageBox.Show(string.Format(LocalizationExtender.GetString(this, "InviteOfflineUser"), contactidstring), LocalizationExtender.GetString(this, "InviteOfflineUserCaption"), MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
        }

        #endregion

        #region Text handling and scrolling

        private void UpdateScrolling()
		{
            if (InvokeRequired)
            {
                BeginInvoke(new ParameterlessHandler(UpdateScrolling));
                return;
            } 
            
            if (!mUpdateSrolling)
            {
                if (scrollBlinkTimer == null)
                {
                    scrollBlinkTimer = new Timer();
                    scrollBlinkTimer.Interval = 500;
                    scrollBlinkTimer.Tick += new EventHandler(scrollBlinkTimer_Tick);
                }

                scrollBlinkTimer.Start();
                return;
            }

            //ugly:(
            tbInComing.VScroll -= new EventHandler(tbInComing_VScroll);
			try
			{
				tbInComing.ScrollToCaret();
			}
			catch (Exception ex)
			{
				mChatControlManager.Host.LogManager.WriteError(this, "Error during UpdateScrolling: " + ex.Message, "ChatController");
			}
            tbInComing.VScroll += new EventHandler(tbInComing_VScroll);

        }

        private void scrollBlinkTimer_Tick(object sender, EventArgs e)
        {
            Font o = tsdbScrollDown.Font;

            if (o.Bold)
            {
                tsdbScrollDown.Image = mDownImage;
				tsdbScrollDown.Font = new Font(o, FontStyle.Regular);
            }
            else
            {
                tsdbScrollDown.Image = mDownImageHigh;
                tsdbScrollDown.Font = new Font(o, FontStyle.Bold);
            }
        }

		//private void SetTextBoxStyle(ExtendedRichTextBox textBox, Font font, Color color)
		//{
		//    if (textBox.InvokeRequired)
		//    {
		//        textBox.BeginInvoke(new SetTextBoxStyleParameteredHandler(SetTextBoxStyle), textBox, font, color);
		//        return;
		//    }
		//    textBox.SelectionLength = 0;
		//    textBox.SelectionStart = textBox.Text.Length;
		//    textBox.SelectionColor = color;
		//    textBox.SelectionFont = font;
		//    textBox.BackColor = SystemColors.Window;
		//}
		
		private void AppendText(string text)
        {
            if (tbInComing.InvokeRequired)
            {
                tbInComing.Invoke(new StringParameteredHandler(AppendText), text);
                return;
            }
			
			if (InvokeRequired)
			{
				Invoke(new StringParameteredHandler(AppendText), text);
				return;
			}

            tbInComing.AppendText(text);

            UpdateScrolling();
        }

		private void AppendErrorText(IMessage message)
		{
			string text = message.Body;
            string initial = string.Empty;

            if (message.Extensions["Error"] != null && message.Extensions["Error"].ToString().Contains("unavailable"))
            {
                initial = "Looks like the recipient doesn't exist. Your message won't be delivered.";
            }

			tbInComing.SetStyle(mChatConfiguration.OtherTextFont, Color.Red);

			if (text.Length > 1000)
			{
				text = string.Format("{0}...", text.Substring(0, 997));
			}
			AppendText(string.Format("{0} ({1})", initial/*Verety.Constellation.Localization.LocalizationExtender.GetString(this, "MessageError")*/, text));
		}

        private void AppendErrorText(string message)
        {
            string text = message;

			tbInComing.SetStyle(mChatConfiguration.OtherTextFont, Color.Red);

            if (text.Length > 1000)
            {
                text = string.Format("{0}...", text.Substring(0, 997));
            }
            AppendText(string.Format("Error: {0}",  text));
        }

        private void AddIncomingText(IMessage message)
        {
            this.SuspendLayout();
			tbInComing.SetStyle(mChatConfiguration.OtherTextFont, mChatConfiguration.OtherTextColor);
            if (Conversation is IConference)
            {
                if (((Conversation as IConference).Owner).Name == message.Sender.Name)
                {
                    tbInComing.SetStyle(mChatConfiguration.OwnerOtherTextFont, mChatConfiguration.OwnerOtherTextColor);
                }
            }
			string userName = message.Sender.User;
			if (userName == null)
			{
				userName = string.Empty;
			}
			if (conferenceMembers.ContainsKey(userName))
			{
				userName = conferenceMembers[userName];
			}
			if (userName.Contains("__"))
			{
				userName = string.Format("{0} ({1})", userName.Substring(0, userName.LastIndexOf("__")), userName.Substring(userName.LastIndexOf("__") + 2));
			}

			if (message.GetProperty("X") != null)
			{
				if ((message.GetProperty("X") as XmlElement).ChildNodes.Count > 0)
					foreach (XmlNode node in (message.GetProperty("X") as XmlElement).ChildNodes[0].ChildNodes)
					{
						if (node.Name == "store")
						{
							userName = string.Format("Store realted message (Store: {0})", node.InnerText);
						}
					}
			}
            AppendText(userName + " (" + DateTime.Now.ToShortTimeString() + "): ");

            Font font = mChatConfiguration.IncomingMessageFont;
            Color fontColor = mChatConfiguration.InComingMessageColor;

            if (Conversation is IConference)
            {
                if (((Conversation as IConference).Owner).Name == message.Sender.Name)
                {
                    font = mChatConfiguration.OwnerMessageFont;
                    fontColor = mChatConfiguration.OwnerMessageColor;
                }
            }

            foreach (XmlNode xn in (message as XmlNode).ChildNodes)
            {
                if (xn.Name == "FontInfo")
                {
                    try
                    {
                        fontColor = Color.FromArgb(int.Parse(xn.Attributes["Color"].Value));
                        float size = float.Parse(xn.Attributes["FontSize"].Value);
                        if (size>40 || size<0) size = 10;
                        font = new Font(xn.Attributes["Font"].Value, size);
                        bool bold = bool.Parse(xn.Attributes["FontBold"].Value);
                        bool italic = bool.Parse(xn.Attributes["FontItalic"].Value);

                        FontStyle fs = FontStyle.Regular;

                        if (bold)
                        {
                            fs |= FontStyle.Bold;
                        }
                        if (italic)
                        {
                            fs |= FontStyle.Italic;
                        }

                        font = new Font(font, fs);
                    }
                    catch
                    {
                        font = mChatConfiguration.IncomingMessageFont;
                        fontColor = mChatConfiguration.InComingMessageColor;
                    }
                }
            }

            tbInComing.SetStyle(font, fontColor);
            AppendText(message.Body + "\n");
            this.ResumeLayout();
        }

        private void SendMessage()
        {
            if (tbInComing.CountOfEmoticons(meOutgoing.Text) > ExtendedRichTextBox.MaxNumberOfEmoticons)
            {
                string text = LocalizationExtender.GetString(this, "TooManyEmoticons");
                if (text.Contains("{0}"))
                {
                    text = string.Format(text, ExtendedRichTextBox.MaxNumberOfEmoticons);
                }
                string header = LocalizationExtender.GetString(this, "TooManyEmoticonsHeader");
                MessageBox.Show(text, header, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            string message = meOutgoing.Text.ToString();

            char[] mess = message.ToCharArray();

            for (int i = 0; i < mess.Length; i++)
            {
                if (Char.ConvertToUtf32(message, i) < 32)
                {
                    mess[i] = '.';
                }
            }

            message = new string(mess);

            if (Conversation is IConference)
            {
                if (((Conversation as IConference).Owner).Name == mDirectoryService.Connection.UserName)
                {
                    tbInComing.SetStyle(mChatConfiguration.OwnerOtherTextFont, mChatConfiguration.OwnerOtherTextColor);
                }
            }
            else
            {
                tbInComing.SetStyle(mChatConfiguration.OtherTextFont, mChatConfiguration.OtherTextColor);
            }
            AppendText(string.Format("{0} ({1}): ", LocalizationExtender.GetString(this, "Me"), DateTime.Now.ToShortTimeString()));
            tbInComing.SetStyle(mChatConfiguration.OutGoingMessageFont, mChatConfiguration.OutGoingMessageColor);
            //if (Conversation is IConference)
            //{
                //if (((Conversation as IConference).Owner).Name == mDirectoryService.Connection.UserName)
                //{
                //    tbInComing.SetStyle(mChatConfiguration.OwnerMessageFont, mChatConfiguration.OwnerMessageColor);
                //}
            //}
            AppendText(message + "\n");

            IMessage packet = null;

            #region packet = Conversation.SendMessage(message) as IMessage;

            try
            {
                object directoryClient = mDirectoryService.GetType().GetProperty("DirectoryClient", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(mDirectoryService, null);
                XmlDocument document = directoryClient.GetType().GetProperty("Document").GetValue(directoryClient, null) as XmlDocument;
                packet = new DirectoryMessage(document);
                packet.Recipient = mConversation.Receiver.Equals(mDirectoryService.Connection.UserContactId) ? mConversation.Requester : mConversation.Receiver;
				if (Conversation is IConference)
				{
					(packet as DirectoryMessage).Type = jabber.protocol.client.MessageType.groupchat;
					IContactId id = new Verety.DirectoryService.Jabber.ContactJID((Conversation as IConference).Conference.Name, (Conversation as IConference).Conference.Server, null);
					packet.Recipient = id;
				}
                (packet as DirectoryMessage).RouteAddress = mConversation.RouteAddress;
                packet.Body = message;
                packet.Priority = null;

                packet.Extensions.Add("Font", mChatConfiguration.OutGoingMessageFont.Name);
                packet.Extensions.Add("FontSize", (int)mChatConfiguration.OutGoingMessageFont.Size);
                packet.Extensions.Add("FontBold", mChatConfiguration.OutGoingMessageFont.Bold);
                packet.Extensions.Add("FontItalic", mChatConfiguration.OutGoingMessageFont.Italic);
                packet.Extensions.Add("Color", mChatConfiguration.OutGoingMessageColor.ToArgb());

                XmlNode fontInfo = document.CreateNode(XmlNodeType.Element, "FontInfo", "");

                foreach (string str in packet.Extensions.Keys)
                {
                    XmlAttribute node = fontInfo.Attributes[str];
                    if (node == null)
                    {
                        node = fontInfo.OwnerDocument.CreateAttribute(str);
                        fontInfo.Attributes.Append(node);
                    }
                    node.Value = packet.Extensions[str].ToString();
                }

                (packet as XmlElement).AppendChild(fontInfo);

                mDirectoryService.Connection.Send(packet);
			}
            catch
            {
                packet = Conversation.SendMessage(message) as IMessage;
            }


            #endregion

            mLastMessage = meOutgoing.Text;

            meOutgoing.ResetText();
            meOutgoing.Font = mChatConfiguration.OutGoingMessageFont; 
            meOutgoing.ForeColor = mChatConfiguration.OutGoingMessageColor;


            if (chatHistory != null)
            {
                IHistoryEntry he = (mDirectoryService.Conversations as IDirectoryConversationManager).CreateHistoryEntryInstance(packet.TimeStamp, packet.Recipient, currentUserJID, PacketType.Message, packet);
                chatHistory.AddHistoryEntry(he);
            }
        }

        #endregion

        #region UI events

		private void tbInComing_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if (!(e.Alt || e.Control))
			{
				meOutgoing.Focus();
			}
		}

        private void Smileys_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
            if (tsmi != null)
            {
                int start = meOutgoing.SelectionStart;
                int length = meOutgoing.SelectionLength;
                meOutgoing.Text = meOutgoing.Text.Insert(start + length, tsmi.Text);
                meOutgoing.SelectionStart = start + tsmi.Text.Length + length;
                meOutgoing.SelectionLength = 0;
            }
        }

        private void btnHide_Click(object sender, EventArgs e)
        {
            SetConferencePanelVisibility(splitContainer2.Panel1Collapsed);
        }

        private void btnJoin_Click(object sender, EventArgs e)
        {
			if (!(Conversation.Requester.User == mDirectoryService.Connection.UserContactId.User &&
				Conversation.Requester.Server == mDirectoryService.Connection.UserContactId.Server))
			{
				btnJoin.Enabled = false;
				return;
			}
            PartnerSelectControl psc = new PartnerSelectControl(mChatControlManager, this, mChatConfiguration.ShowOfflinesForConference);

            mChatControlManager.Host.Smartparts.Add(psc);
        }

        private void btnSendMessage_Click(object sender, EventArgs e)
        {
            SendMessage();
        }

        private void meOutgoing_Properties_KeyPress(object sender, KeyPressEventArgs e)
        {
			if (meOutgoing.Font != mChatConfiguration.OutGoingMessageFont)
			{
				meOutgoing.Font = mChatConfiguration.OutGoingMessageFont;
			}
			if (meOutgoing.ForeColor != mChatConfiguration.OutGoingMessageColor)
			{
				meOutgoing.ForeColor = mChatConfiguration.OutGoingMessageColor;
			}
			if (e.KeyChar == (char)Keys.Enter)
            {
                if (meOutgoing.Text != string.Empty)
                {
                    SendMessage();
                }
                e.Handled = true;
            }
        }

        private void meOutgoing_EditValueChanged(object sender, EventArgs e)
        {
            btnSendMessage.Enabled = meOutgoing.Text != string.Empty;
        }

        private void tbInComing_LinkClicked(object sender, LinkClickedEventArgs e)
        {
            try
            {
                IWebBrowserService wbs = mChatControlManager.Services.Get<IWebBrowserService>();
				if (wbs == null)
				{
					System.Diagnostics.Process.Start(e.LinkText);
					return;
				}
                wbs.OpenURL(e.LinkText, true);
            }
            catch
            {
                System.Diagnostics.Process.Start(e.LinkText);
            }
        }

		private void tbConferenceName_Leave(object sender, EventArgs e)
        {
            string correctedString = string.Empty;

            for (int i = 0; i < tbConferenceName.Text.Length; i++)
                if (Char.IsLetterOrDigit(tbConferenceName.Text, i))
                    correctedString += tbConferenceName.Text[i];
                else
                    correctedString += ' ';

            tbConferenceName.Text = correctedString;

            if (tbConferenceName.Text.Length == 0)
                tbConferenceName.Text = oldConferenceName;

            if ((Conversation is IConference) && (Conversation as IConference).Owner.ToString() == Conversation.Messenger.Connection.UserContactId.ToString() && oldConferenceName != tbConferenceName.Text)
            {
                RenameConference();
            }
        }

		private void tbConferenceName_Enter(object sender, EventArgs e)
        {
            oldConferenceName = tbConferenceName.Text;
        }

		private void inviteUsersToolStripMenuItem_Click(object sender, EventArgs e)
        {
			if (string.IsNullOrEmpty(Conversation.Partner.Resource) && !(Conversation is IConference))
			{
				string offlineWarning = LocalizationExtender.GetString(this, "OfflineWarningForConvertToConference");
				if (string.IsNullOrEmpty(offlineWarning))
				{
					offlineWarning = "User is unavailable. Cannot invite other contact.";
				}
				AppendText("\n");
				tbInComing.SetStyle(mChatConfiguration.OtherTextFont, Color.Red);
				AppendText(string.Format("{0}\n\n", offlineWarning));
				return;
			}
            (mConversation as IConversation).ConvertToConference();
            btnJoin_Click(sender, e);
        }

        private void tbInComing_VScroll(object sender, EventArgs e)
        {
            mUpdateSrolling = false;
			tsdbScrollDown.Visible = true;
        }

        private void ChatControl_Disposed(object sender, EventArgs e)
        {
            mDockControl_Closed(sender, e);
        }

		private void mDockControl_Closed(object sender, EventArgs e)
        {
            Closed -= new EventHandler(mDockControl_Closed);

            if (chatHistory != null)
            {
                ChatHistoryManager.CloseHistory(chatHistory);
                chatHistory = null;
            }

            mConversation.Close();

            Dispose(true);
        }

        private void mDockControl_Closing(object sender, EventArgs e)
        {
            mChatControlPositionInfo.FloatingLocation = FloatingLocation;
            mChatControlPositionInfo.FloatingSize = FloatingSize;
            mChatControlPositionInfo.InitialAppearanceStyle = CurrentAppearanceStyle;
            mChatControlPositionInfo.InitialDockStyle = Dock;
        }

		private void ChatControl_VisibleChanged(object sender, EventArgs e)
		{
			if (this.Visible)
			{
				meOutgoing.Focus();
			}
		}

        private void meOutgoing_KeyPress(object sender, KeyPressEventArgs e)
        {
            //if (e.!string.IsNullOrEmpty(mLastMessage))
            //{
            //    int position = meOutgoing.SelectionStart + meOutgoing.SelectionLength;

            //    meOutgoing.Text = meOutgoing.Text.Insert(position, mLastMessage);
            //    meOutgoing.SelectionStart = position + mLastMessage.Length;
            //    meOutgoing.SelectionLength = 0;
            //}
        }

		private void tsdbScrollDown_Click(object sender, EventArgs e)
		{
			mUpdateSrolling = true;
			tsdbScrollDown.Visible = false;
            tsdbScrollDown.Image = mDownImage;

			if (scrollBlinkTimer != null)
				scrollBlinkTimer.Stop();

			UpdateScrolling();
		}

        #endregion

        #region Constructors
		internal ChatControl(IConversation conversation, ChatControllerModule chatControlManager, IDirectoryService directoryService, ChatControlPositionInfo ccpi)
			: this(conversation, chatControlManager, directoryService)
		{
			try
			{
				FloatingLocation = ccpi.FloatingLocation;
			}
			catch (Exception ex)
			{
				chatControlManager.Host.LogManager.WriteWarning(this, "Error during initializing chat location (" + ccpi.FloatingLocation + "): " + ex.Message, "ChatController");
			}
			try
			{
				FloatingSize = ccpi.FloatingSize;
			}
			catch (Exception ex)
			{
                chatControlManager.Host.LogManager.WriteWarning(this, "Error during initializing chat size (" + ccpi.FloatingSize + "): " + ex.Message, "ChatController");
			}
			try
			{
				InitialAppearanceStyle = ccpi.InitialAppearanceStyle;
			}
			catch (Exception ex)
			{
                chatControlManager.Host.LogManager.WriteWarning(this, "Error during initializing chat style (" + ccpi.InitialAppearanceStyle + "): " + ex.Message, "ChatController");
			}
			try
			{
				InitialDock = ccpi.InitialDockStyle;
			}
			catch (Exception ex)
			{
                chatControlManager.Host.LogManager.WriteWarning(this, "Error during initializing chat dock (" + ccpi.InitialDockStyle + "): " + ex.Message, "ChatController");
			}
		}

        private Bitmap GenerateAlphaBlendedImage(Image image, float alpha)
        {
            Bitmap bmp = new Bitmap(image.Width, image.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.FillEllipse(Brushes.Orange, 0, 0, image.Width-1, image.Height-1);
            //g.FillRectangle(Brushes.Orange, new Rectangle(0, 0, image.Width, image.Height));
            ColorMatrix cm = new ColorMatrix();
            cm.Matrix00 = cm.Matrix11 = cm.Matrix22 = cm.Matrix44 = 1;
            cm.Matrix33 = alpha;
            ImageAttributes ia = new ImageAttributes();
            ia.SetColorMatrix(cm);
            g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, ia);
            
            return bmp;
        }

        public ChatControl(IConversation conversation, ChatControllerModule chatControlManager, IDirectoryService directoryService) : base(chatControlManager)
        {
            mChatControlManager = chatControlManager;

            InitializeComponent();

            BorderStyle = SBPweb.Modules.Smartparts.BorderStyle.Sizable;
            HideOnlyWhenClose = false;
            IsShowInWindowMenu = false;

            MinimumSize = new Size(100, 400);

            Tag = new Random().Next();

            mChatConfiguration = chatControlManager.ChatConfiguration;

            meOutgoing.Font = mChatConfiguration.OutGoingMessageFont;
            meOutgoing.ForeColor = mChatConfiguration.OutGoingMessageColor;

            mDownImage = new Bitmap(SBPweb.Modules.ChatController.Properties.Resources.Button_Down_16x16);
            mDownImageHigh = GenerateAlphaBlendedImage(mDownImage, 0.6f);
            mDownImage.MakeTransparent(mDownImage.GetPixel(0, 0));
            mDownImageHigh.MakeTransparent(mDownImageHigh.GetPixel(0, 0));

            tsdbScrollDown.Click += new System.EventHandler(this.tsdbScrollDown_Click);
            tsdbScrollDown.DisplayStyle = ToolStripItemDisplayStyle.Image;
            tsdbScrollDown.Image = mDownImage;
            tsdbScrollDown.ToolTipText = "Scroll Down";

            tbConferenceName.Enter += new EventHandler(tbConferenceName_Enter);
            tbConferenceName.Leave += new EventHandler(tbConferenceName_Leave);
            tbInComing.LinkClicked += new LinkClickedEventHandler(tbInComing_LinkClicked);

            tbInComing.ScrollBars = RichTextBoxScrollBars.ForcedVertical;
            tbInComing.VScroll -= new EventHandler(tbInComing_VScroll);
            tbInComing.VScroll += new EventHandler(tbInComing_VScroll);

            Closing += new EventHandler(mDockControl_Closing);
            Closed += new EventHandler(mDockControl_Closed);
            Disposed += new EventHandler(ChatControl_Disposed);

            Dock = DockStyle.Fill;

            tbInComing.Emoticons = chatControlManager.Smileys as ImageCollection;

            SetCaptions(Caption);

            ChatHistoryManager.DirectoryService = mDirectoryService = directoryService;

            currentUserJID = directoryService.Connection.UserContactId; //new jabber.JID(directoryService.Connection.UserName, directoryService.Connection.Server, directoryService.Connection.Resource);

            Conversation = conversation;

            if (Conversation is IConference && (Conversation as IConference).Owner.ToString() == Conversation.Messenger.Connection.UserContactId.ToString())
            {
                RenameConference();
            }

            if (!Conversation.Requester.ToString().Equals(Conversation.Messenger.Connection.UserContactId.ToString()))
            {
                tbConferenceName.Enabled = false;
            }

            if (chatHistory != null && mChatConfiguration.ShowHistory && mDirectoryService.Security.Authorize("Visibility:HistoryInChat"))
            {
                string history = LocalizationExtender.GetString(this, "History");
                string endhistory = LocalizationExtender.GetString(this, "EndHistory");
                string historyString = chatHistory.GetMessagesAsString(mChatConfiguration.HistoryLines);
                if (historyString.Length > 0)
                {
                    tbInComing.SetStyle(mChatConfiguration.ChatHistoryOtherTextFont, mChatConfiguration.ChatHistoryOtherTextColor);
                    AppendText(string.Format("{0}\n\n", history));
                    string[] lines = historyString.Split("\n".ToCharArray());
                    foreach (string line in lines)
                    {
                        tbInComing.SetStyle(mChatConfiguration.ChatHistoryTextFont, mChatConfiguration.ChatHistoryTextColor);
                        AppendText(string.Format("{0}\n", line));
                    }
                    tbInComing.SetStyle(mChatConfiguration.ChatHistoryOtherTextFont, mChatConfiguration.ChatHistoryOtherTextColor);
                    AppendText(string.Format("{0}\n\n", history, historyString, endhistory));
                }
            }

            tbInComing.SetStyle(mChatConfiguration.OtherTextFont, Color.Red);
            if (string.IsNullOrEmpty(Conversation.Partner.Resource) && !(Conversation is IConference))
            {
                if (mDirectoryService.Contacts.CheckIfUserExists(mConversation.Partner))
                {
                    string offlineWarning = LocalizationExtender.GetString(this, "OfflineWarning");
                    if (string.IsNullOrEmpty(offlineWarning))
                    {
                        offlineWarning = "User is unavailable. Your message will be sent offline.";
                    }
                    AppendText("\n");
                    tbInComing.SetStyle(mChatConfiguration.OtherTextFont, Color.Red);
                    AppendText(string.Format("{0}\n\n", offlineWarning));
                }
                else
                {
                    if (mFirstError)
                    {
                        string partnerDoesntExistError = LocalizationExtender.GetString(this, "PartnerDoesntExistError");
                        if (string.IsNullOrEmpty(partnerDoesntExistError))
                        {
                            partnerDoesntExistError = "Looks like your partner doesn't exist.";
                        }
                        AppendErrorText(partnerDoesntExistError);
                        btnSendMessage.Enabled = false;
                        Enabled = false;
                        mFirstError = false;
                    }
                }
            }

            toolStripDropDownButton1.Image = mChatControlManager.Smileys[":)"] as Image;
            foreach(System.Collections.DictionaryEntry item in mChatControlManager.Smileys)
            {
                if (!item.Key.ToString().StartsWith("[") && !item.Key.ToString().EndsWith("["))
                {
                    ToolStripMenuItem tsmi = new ToolStripMenuItem();
                    tsmi.Text = item.Key as string;
                    tsmi.Image = item.Value as Image;
                    tsmi.ImageScaling = ToolStripItemImageScaling.None;
                    tsmi.ImageAlign = ContentAlignment.MiddleCenter;
                    tsmi.Click += new EventHandler(Smileys_Click);
                    tsmi.TextAlign = ContentAlignment.MiddleCenter;
                    toolStripDropDownButton1.DropDownItems.Add(tsmi);
                }
            }

            AutoValidate = AutoValidate.Disable;
            this.VisibleChanged += new EventHandler(ChatControl_VisibleChanged);
            meOutgoing.KeyPress += new KeyPressEventHandler(meOutgoing_KeyPress);

            meOutgoing.Focus();

        }

        #endregion
    }
}
